package nz.ac.massey.doi_information_extractor.parser;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.lang3.StringEscapeUtils;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import nz.ac.massey.doi_information_extractor.data.Author;
import nz.ac.massey.doi_information_extractor.data.AuthorList;
import nz.ac.massey.doi_information_extractor.data.Publication;

public class CrossrefPlugin implements PluginInterface {

	private String doi;
	private Document document;
	private XPath query;
	public Publication result = new Publication();

	public CrossrefPlugin(String doi) {
		this.doi = doi;
	}

	@Override
	public Publication call() throws Exception {
		getInformationFromDOI(doi);
		return result;
	}

	@Override
	public void getInformationFromDOI(String doi)
			throws PublicationNotFoundException, IOException {
		String url = "http://www.crossref.org/openurl/?id=doi:" + doi
				+ "&noredirect=true&pid=dollar10boy@hotmail.com&format=unixref";

		// Get the page with search results for the DOI.
		URL searchPage;
		try {
			searchPage = new URL(url);
		} catch (MalformedURLException e) {
			throw new PublicationNotFoundException(e.getMessage());
		}

		InputStream buffer = searchPage.openConnection().getInputStream();

		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			this.document = builder.parse(buffer);
		} catch (ParserConfigurationException ex) {
			throw new PublicationNotFoundException(ex.getMessage());
		} catch (SAXException ex) {
			throw new PublicationNotFoundException(ex.getMessage());
		} catch (Exception ex) {
			throw new PublicationNotFoundException(ex.getMessage());
		}

		query = XPathFactory.newInstance().newXPath();

		String error;
		try {
			error = (String) query.evaluate("//error", document,
					XPathConstants.STRING);
		} catch (XPathExpressionException ex) {
			error = "";
		}

		if (error != "") {
			throw new PublicationNotFoundException("Crossref: Unable to resolve doi");
		}

		try {
			parseDocument();
		} catch (XPathExpressionException ex) {
			throw new PublicationNotFoundException("Crossref: error parsing results");
		}
	}

	private void parseDocument() throws XPathExpressionException,
			PublicationNotFoundException {
		String temp = (String) query.evaluate("//journal", document,
				XPathConstants.STRING);

		if (temp != "")
			parseJournal();
		else {
			temp = (String) query.evaluate("//book", document,
					XPathConstants.STRING);
			if (temp != "") {
				parseBook();
			} else {
				temp = (String) query.evaluate("//conference", document,
						XPathConstants.STRING);
				if (temp != "") {
					parseConference();
				} else {
					throw new PublicationNotFoundException(
							"Crossref: Error parsing results");
				}
			}
		}
	}

	private String getConferenceDates() {

		return "";
	}

	private void parseJournal() throws XPathExpressionException {
		result.setPublicationType("journal");

		result.setPublicationTitle( StringEscapeUtils.unescapeHtml4((String) query.evaluate("//full_title",
				document, XPathConstants.STRING)));

		result.setIssn((String) query.evaluate("//issn", document,
				XPathConstants.STRING));

		result.setDate(getDate());

		result.setVolumeNumber((String) query.evaluate("//volume", document,
				XPathConstants.STRING));

		result.setEdition((String) query.evaluate("//issue", document,
				XPathConstants.STRING));

		result.setArticleTitle(StringEscapeUtils.unescapeHtml4((String) query.evaluate("//title", document,
				XPathConstants.STRING)));

		result.setAuthors(getAuthors());

		result.setPageNumbers(getPages());

		result.setUrl((String) query.evaluate("//resource", document,
				XPathConstants.STRING));

		/*
		 * result.setPublicationTitle(getElementValue("full_title"));
		 *
		 * result.setIssn(getElementValue("issn"));
		 *
		 * result.setDate(getDate());
		 *
		 * result.setVolumeNumber(getElementValue("volume"));
		 *
		 * result.setJournalEdition( getElementValue("issue"));
		 *
		 * result.setArticleTitle(getElementValue("title"));
		 *
		 * result.setAuthors(getAuthors());
		 *
		 * result.setPageNumbers(getPages());
		 *
		 * result.setUrl(getElementValue("resource"));
		 */
	}

	private void parseBook() throws XPathExpressionException {
		result.setPublicationType("book");

		result.setPublicationTitle(StringEscapeUtils.unescapeHtml4((String) query.evaluate("//title", document,
				XPathConstants.STRING)));

		result.setIssn((String) query.evaluate("//isbn", document,
				XPathConstants.STRING));

		result.setAuthors(getAuthors());

		result.setUrl((String) query.evaluate("//resource", document,
				XPathConstants.STRING));

		result.setDate(getDate());

		result.setPublisher(StringEscapeUtils.unescapeHtml4((String) query.evaluate("//publisher_name",
				document, XPathConstants.STRING)));

		result.setPublisherLocation(StringEscapeUtils.unescapeHtml4((String) query.evaluate(
				"//publisher_place", document, XPathConstants.STRING)));

		result.setEdition((String) query.evaluate("//edition_number", document,
				XPathConstants.STRING));
		/*
		 * result.setPublicationTitle(getElementValue("title"));
		 *
		 * result.setIssn(getElementValue("isbn"));
		 *
		 * result.setAuthors(getAuthors());
		 *
		 * result.setUrl(getElementValue("resource"));
		 *
		 * result.setDate(getDate());
		 *
		 * result.setPublisher(getElementValue("publisher_name"));
		 *
		 * result.setPublisherLocation(getElementValue("publisher_place"));
		 *
		 * result.setJournalEdition(getElementValue("edition_number"));
		 */
	}

	private void parseConference() throws XPathExpressionException {
		result.setPublicationType("conference");

		result.setPublicationTitle(StringEscapeUtils.unescapeHtml4((String) query.evaluate("//conference_name",
				document, XPathConstants.STRING)));

		result.setConferenceLocation(StringEscapeUtils.unescapeHtml4((String) query.evaluate(
				"//conference_location", document, XPathConstants.STRING)));

		result.setAuthors(getAuthors());

		result.setUrl((String) query.evaluate("//resource", document,
				XPathConstants.STRING));

		result.setIssn((String) query.evaluate("//issn", document,
				XPathConstants.STRING));

		result.setEdition((String) query.evaluate("//volume", document,
				XPathConstants.STRING));

		result.setArticleTitle(StringEscapeUtils.unescapeHtml4((String) query.evaluate("//proceedings_title",
				document, XPathConstants.STRING)));

		result.setConferenceDates(getConferenceDates());
		/*
		 * result.setPublicationTitle(getElementValue("conference_name"));
		 *
		 * result.setConferenceLocation(getElementValue("conference_location"));
		 *
		 * result.setAuthors(getAuthors());
		 *
		 * result.setUrl(getElementValue("resource"));
		 *
		 * result.setIssn(getElementValue("issn"));
		 *
		 * result.setJournalEdition(getElementValue("volume"));
		 *
		 * result.setArticleTitle(getElementValue("proceedings_title"));
		 *
		 * result.setConferenceDates(getConferenceDates());
		 */
	}

	private String getDate() {
		String day = "";
		String month = "";
		String year = "";
		try {
			day = (String) query.evaluate("//publication_date//day", document,
					XPathConstants.STRING);
			month = (String) query.evaluate("//publication_date//month",
					document, XPathConstants.STRING);
			year = (String) query.evaluate("//publication_date//year",
					document, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			return "";
		}

		return day + "/" + month + "/" + year;
	}

	private AuthorList getAuthors() {
		AuthorList authors = new AuthorList();

		Node list = null;
		try {
			list = (Node)query.evaluate("//contributors", document,XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			return authors;
		}
		NodeList rootChildNodes = list.getChildNodes();

		for(int i = 0; i < rootChildNodes.getLength();i++){
			if(rootChildNodes.item(i).getNodeName().equals("person_name")){
				String firstName = "";
				String lastName = "";

				NodeList childNodes = rootChildNodes.item(i).getChildNodes();

				for(int j = 0; j < childNodes.getLength(); j++){

					if(childNodes.item(j).getNodeName().equals("given_name")){
						StringEscapeUtils.unescapeHtml4(firstName = childNodes.item(j).getFirstChild().getNodeValue());
					}else if(childNodes.item(j).getNodeName().equals("surname")){
						lastName = StringEscapeUtils.unescapeHtml4(childNodes.item(j).getFirstChild().getNodeValue());
					}
				}
				Author newAuthor = new Author();
				newAuthor.setAuthorFirstName(firstName);
				newAuthor.setAuthorLastName(lastName);
				authors.add(newAuthor);
			}
		}

		return authors;
	}



	private String getPages() {
		String firstPage = "";
		String lastPage = "";
		try {
			firstPage = (String) query.evaluate("//pages//first_page",
					document, XPathConstants.STRING);
			lastPage = (String) query.evaluate("//pages//last_page",
					document, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			return "";
		}
		return firstPage + "-" + lastPage;
	}

}
